#pragma once

#include "../../inc/TopoDS/OMIT_MeshForwardDecl.h"

#include <range/v3/range.hpp>

namespace OMIT_NAMESPACE
{
    template <typename Impl, typename TD, typename TV>
    class MeshIteratorBase
    {
    public:
		using value_type = TV;
		using difference_type = std::ptrdiff_t;
		using pointer = std::add_pointer_t<value_type>;
		using reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
		using iterator_category = std::forward_iterator_tag;

		constexpr MeshIteratorBase(TD data, bool is_begin) noexcept : _data{ data }, _is_begin{ is_begin } {}
		constexpr MeshIteratorBase() noexcept : _data{ nullptr }, _is_begin{ false } {}
		friend constexpr bool operator==(const Impl& lhs, const Impl& rhs) noexcept 
			{ return lhs._data == rhs._data && lhs._is_begin == rhs._is_begin; }
		friend constexpr bool operator!=(const Impl& lhs, const Impl& rhs) noexcept { return !(lhs == rhs); }
		value_type operator->() const noexcept { return Impl::Value(_data); }
		value_type operator*() const noexcept { return Impl::Value(_data); }
		Impl& operator++() noexcept { _data = Impl::Next(_data); _is_begin = false; return *static_cast<Impl*>(this); }
		Impl operator++(int) noexcept { Impl rst = *static_cast<Impl*>(this); this->operator++(); return rst; }

	private:
		TD _data{};
		bool _is_begin{};
    };


	template <typename Impl, typename TD, typename TV>
		class MeshViewBase : public ranges::view_base
	{
	public:
		class Iterator : public MeshIteratorBase<Iterator, TD, TV>
		{
		public:
			using MeshIteratorBase<Iterator, TD, TV>::MeshIteratorBase;
		private:
			friend MeshIteratorBase<Iterator, TD, TV>;
			static TV Value(TD data) noexcept { return Impl::Value(data); }
			static TD Next(TD data) noexcept { return Impl::Next(data); }
		};

		constexpr MeshViewBase(TD begin_value, TD end_value) noexcept
			: _begin_value{ begin_value }, _end_value{ end_value } {}
		constexpr MeshViewBase() noexcept
			: _begin_value{ nullptr }, _end_value{ nullptr } {}

		Iterator begin() const noexcept { return _begin_value ? Iterator{ _begin_value, true } : Iterator{}; }
		Iterator end() const noexcept { return { _end_value, false }; }

	private:
		TD _begin_value{};
		TD _end_value{};
	};
}
